/**
* @author DavidLee 
* @title getError
* @date 2024-10-10 18-31-08
* @description 从HTTP请求的XMLHttpRequest对象中提取错误信息，并返回一个新的Error对象
* @param  action：请求的操作类型  
* @param  option：请求的选项
* @param  xhr：XMLHttpRequest对象（包含了HTTP请求的详细信息，包括响应状态、响应数据等）
* @return Error对象
*/
function getError(action, option, xhr) {
  let msg;
  if (xhr.response) {
    msg = `${xhr.response.error || xhr.response}`;
  } else if (xhr.responseText) {
    msg = `${xhr.responseText}`;
  } else {
    // ${action}是请求的操作类型  ${xhr.status}是HTTP响应的状态码
    msg = `fail to ${action} ${xhr.status}`;
  }

  return new Error(msg);
}

/**
* @author DavidLee 
* @title getBody
* @date 2024-10-10
* @description 从XMLHttpRequest对象（xhr）中提取响应体，并尝试将其解析为JSON对象。如果解析失败，则返回原始的响应文本
* @param  xhr：XMLHttpRequest对象（包含了HTTP请求的详细信息，包括响应状态、响应数据等）
* @return text（可能是一个JSON对象或原始的响应文本）
*/
function getBody(xhr) {
  // xhr.responseText是获取响应文本的常用属性
  // xhr.response中也可能存储响应数据
  const text = xhr.responseText || xhr.response;
  if (!text) {
    return text;
  }

  try {
    return JSON.parse(text);
  } catch (e) {
    return text;
  }
}

/**
* @author DavidLee 
* @title upload
* @date 2024-10-10
* @description 用于通过XMLHttpRequest对象实现文件上传功能
* @param  option：请求的选项
* @return XMLHttpRequest对象
*/
export default function upload(option) {
  const xhr = new XMLHttpRequest();  // 用于发送HTTP请求
  const action = option.action;

  if (xhr.upload) {                                 // 若xhr.upload存在，
    xhr.upload.onprogress = function progress(e) {  // 设置onprogress事件监听器，用于监听上传进度
      if (e.total > 0) {
        e.percent = e.loaded / e.total * 100;
      }
      option.onProgress(e);  // 计算上传百分比并调用option.onProgress回调函数
    };
  }

  const formData = new FormData();  // 使用FormData对象来构建上传的数据，包括文件和其他数据。

  if (option.data) {                               // 若option.data存在
    Object.keys(option.data).forEach(key => {      // 将不同键及其数据添加到FormData对象中
      formData.append(key, option.data[key]);
    });
  }

  formData.append(option.filename, option.file, option.file.name);  // 将文件添加到FormData对象中

  xhr.onerror = function error(e) {  // 通过xhr.onerror设置错误处理函数
    option.onError(e);               // 当请求发生错误时调用option.onError回调函数
  };

  xhr.onload = function onload() {   // 通过xhr.onload设置请求完成处理函数
    if (xhr.status < 200 || xhr.status >= 300) {                // 若HTTP响应状态码不在200-300之间
      return option.onError(getError(action, option, xhr));     // 调用getError函数获取错误信息，并调用option.onError回调函数
    }

    option.onSuccess(getBody(xhr));  // 当请求完成时调用option.onSuccess回调函数，并处理响应数据
  };

  xhr.open('post', action, true);    // 通过xhr.open设置请求方法为POST，请求地址为action，第三个参数为true表示异步请求

  if (option.withCredentials && 'withCredentials' in xhr) {  // 如果有允许跨域请求发送标志位，则将xhr.withCredentials设置为true
    xhr.withCredentials = true;
  }

  const headers = option.headers || {};    // 获取请求头信息

  for (let item in headers) {
    if (headers.hasOwnProperty(item) && headers[item] !== null) {   
      xhr.setRequestHeader(item, headers[item]);   // 遍历请求头信息，将非空属性添加到xhr.setRequestHeader中
    }
  }
  xhr.send(formData);    // 通过xhr.send发送请求，将FormData对象作为请求体传递出去
  return xhr;
}
